package org.teremail.service;

import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.teremail.common.Log;

public class ServiceManager implements ServiceManagerMBean {

    private final static Log log = Log.getLog(ServiceManager.class);
    private final CountDownLatch latch = new CountDownLatch(1);
    private final List<Service> services;
    private ServiceAction lastAction = null;
    
    public ServiceManager(List<Service> services) {
        this.services = services;
    }

    public void run(ServiceAction action) {
        try {
            if (lastAction != action) {                
                for (Service service : services) {
                    log.info("Running %s on %s", action, service.getClass().getName());
                    action.run(service);
                }
                lastAction = action;
            }
        } catch (Exception e) {
            log.equals(e);
        }
    }

    public void startAll() {
        
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
                stopAll();
            }
        });
        
        run(ServiceAction.START);
    }
    
    public void stopAll() {
        try {
            run(ServiceAction.STOP);
        } finally {
            latch.countDown();
        }
    }

    @Override
    public void bindAll() {
        run(ServiceAction.BIND);
    }

    @Override
    public void unbindAll() {
        run(ServiceAction.UNBIND);
    }

    @Override
    public void waitForShutdown() throws InterruptedException {
        latch.await();
    }

    private enum ServiceAction {
        START {
            public void run(Service service) throws Exception {
                service.start();
            }
        },
        STOP {
            public void run(Service service) throws Exception {
                service.stop();
            }
        }, 
        BIND {
            public void run(Service service) throws Exception {
                service.bind();
            }
        }, 
        UNBIND {
            public void run(Service service) throws Exception {
                service.unbind();
            }
        };
        
        public abstract void run(Service service) throws Exception;
    }
    
}
